package com.micro.plugins.oshi;

import com.micro.plugins.oshi.model.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

/**
 * @author LevelCoder
 * @version V1.0.0
 * @email LevelCoder@126.com
 * @date 2020/6/25
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ServerInfo {

    private static final int OSHI_WAIT_SECOND = 1000;

    /**
     * CPU相关信息
     */
    private CpuInfo cpuInfo = new CpuInfo();

    /**
     * JVM相关信息
     */
    private JvmInfo jvmInfo = new JvmInfo();

    /**
     * 內存相关信息
     */
    private MemoryInfo memoryInfo = new MemoryInfo();

    /**
     * 服务器相关信息
     */
    private SystemBaseInfo systemBaseInfo = new SystemBaseInfo();

    /**
     * 磁盘相关信息
     */
    private List<SystemFileInfo> systemFileInfoList = new LinkedList<SystemFileInfo>();

    /**
     * 获取服务信息
     */
    public void info() throws UnknownHostException {
        SystemInfo systemInfo = new SystemInfo();
        HardwareAbstractionLayer hardware = systemInfo.getHardware();
        installCpuInfo(hardware.getProcessor());
        installMemoryInfo(hardware.getMemory());
        installSystemBaseInfo();
        installJvmInfo();
        installSystemFileInfo(systemInfo.getOperatingSystem());
    }

    /**
     * <h2>设置cpu相关信息</h2>
     * @param processor
     */
    private void installCpuInfo(CentralProcessor processor) {
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        cpuInfo.setCpuCoreNum(processor.getLogicalProcessorCount());
        cpuInfo.setCpuFreeRate(new DecimalFormat("#.##%").format(1.0-(idle * 1.0 / totalCpu)));
        cpuInfo.setCpuSysUseRate(new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu));
        cpuInfo.setCpuUserUsage(new DecimalFormat("#.##%").format(user * 1.0 / totalCpu));
        cpuInfo.setCpuWaitRate(new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu));
    }


    /**
     * <h2>设置内存相关信息</h2>
     * @param memory
     */
    private void installMemoryInfo(GlobalMemory memory) {
        //总内存
        long totalByte = memory.getTotal();
        //剩余
        long acaliableByte = memory.getAvailable();
        memoryInfo.setMemTotalCapacity(formatByte(totalByte));
        memoryInfo.setMemUsedCapacity(formatByte(totalByte-acaliableByte));
        memoryInfo.setMemFreeCapacity(formatByte(acaliableByte));
        memoryInfo.setMemUsedRate(new DecimalFormat("#.##%").format((totalByte-acaliableByte)*1.0/totalByte));
    }

    /**
     * <h2>设置服务器信息</h2>
     */
    private void installSystemBaseInfo() throws UnknownHostException {
        Properties props = System.getProperties();
        systemBaseInfo.setComputerIp(InetAddress.getLocalHost().getHostAddress());
        systemBaseInfo.setComputerName(InetAddress.getLocalHost().getHostName());
        systemBaseInfo.setOsArch(props.getProperty("os.arch"));
        systemBaseInfo.setOsName(props.getProperty("os.name"));
        systemBaseInfo.setUserDir(props.getProperty("user.dir"));
    }

    /**
     * <h2>设置Java虚拟机</h2>
     */
    private void installJvmInfo() {
        Properties props = System.getProperties();
        Runtime runtime = Runtime.getRuntime();
        //jvm总内存
        long jvmTotalMemoryByte = runtime.totalMemory();
        //jvm最大可申请
        long jvmMaxMoryByte = runtime.maxMemory();
        //空闲空间
        long freeMemoryByte = runtime.freeMemory();

        jvmInfo.setJvmName(props.getProperty("java.vm.name"));
        jvmInfo.setJdkPath(props.getProperty("java.home"));
        jvmInfo.setJdkVersion(props.getProperty("java.version"));
        jvmInfo.setJvmFreeMemory(formatByte(freeMemoryByte));
        jvmInfo.setJvmMaximumAvailableMemory(formatByte(jvmMaxMoryByte));
        jvmInfo.setJvmTotalMemoryUsed(formatByte(jvmTotalMemoryByte));
        jvmInfo.setJvmUsedRate(new DecimalFormat("#.##%").format((jvmTotalMemoryByte-freeMemoryByte)*1.0/jvmTotalMemoryByte));
    }

    /**
     * <h2>设置磁盘信息</h2>
     * @param operatingSystem
     */
    private void installSystemFileInfo(OperatingSystem operatingSystem) {
        FileSystem fileSystem = operatingSystem.getFileSystem();
        OSFileStore[] osFileStoreList = fileSystem.getFileStores();
        for (OSFileStore osFileStore : osFileStoreList) {
            long free = osFileStore.getUsableSpace();
            long total = osFileStore.getTotalSpace();
            long used = total - free;
            SystemFileInfo systemFileInfo = new SystemFileInfo();
            systemFileInfo.setDirName(osFileStore.getMount());
            systemFileInfo.setSysTypeName(osFileStore.getType());
            systemFileInfo.setTypeName(osFileStore.getName());
            systemFileInfo.setTotal(formatByte(total));
            systemFileInfo.setFree(formatByte(free));
            systemFileInfo.setUsed(formatByte(used));
            systemFileInfo.setUsage(new DecimalFormat("#.##%").format(used*1.0/total));
            systemFileInfoList.add(systemFileInfo);
        }
    }





    /**
     * 字节转换
     * @param byteNumber
     * @return
     */
    public static String formatByte(long byteNumber){
        //换算单位
        double FORMAT = 1024.0;
        double kbNumber = byteNumber/FORMAT;
        if(kbNumber<FORMAT){
            return new DecimalFormat("#.##KB").format(kbNumber);
        }
        double mbNumber = kbNumber/FORMAT;
        if(mbNumber<FORMAT){
            return new DecimalFormat("#.##MB").format(mbNumber);
        }
        double gbNumber = mbNumber/FORMAT;
        if(gbNumber<FORMAT){
            return new DecimalFormat("#.##GB").format(gbNumber);
        }
        double tbNumber = gbNumber/FORMAT;
        return new DecimalFormat("#.##TB").format(tbNumber);
    }


}
